#pragma once

#include <iostream>
#include <string>
#include <cstring>
#include <cstdlib>
#include <cerrno>
#include <strings.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include "log.hpp"

using namespace std;

namespace Client
{
    static const int g_num = 1024;

    enum
    {
        USAGE_ERROR = 1,
        SOCKET_ERROR,
        CONNECT_ERROR
    };
    class tcpClient
    {
    public:
        tcpClient(const string &serverIP, const uint16_t serverPort) : _sockfd(-1), _serverIP(serverIP), _serverPort(serverPort)
        {
        }
        ~tcpClient()
        {
            if(_sockfd >= 0) close(_sockfd);// 写不写皆可，因为进程打开的文件的生命周期是跟随进程的
        }

        void init()
        {
            // 1. 创建套接字
            _sockfd = socket(AF_INET, SOCK_STREAM, 0); // tcp通信
            if (_sockfd == -1)
            {
                // logMessage(FATAL, "create socket error");// 客户端不再打印日志
                cerr << "create socket error: " << errno << " : " << strerror(errno) << endl;
                exit(SOCKET_ERROR);
            }
            cout << "create socket success" << endl; // 测试

            // 2. 绑定——tcp客户端需要bind，但不需要显式bind

            // 3. tcp客户端需要listen吗？——不需要

            // 4. 客户端需要accept吗？——不需要

            // 5. 客户端需要做什么？——因为tcp通信是面向连接的，所以，tcp客户端要向服务器发起连接
        }
        void run()
        {
            // 5. 发起连接
            struct sockaddr_in server;
            memset(&server, 0, sizeof(server));

            server.sin_family = AF_INET;
            server.sin_addr.s_addr = inet_addr(_serverIP.c_str());
            server.sin_port = htons(_serverPort);

            if (connect(_sockfd, (struct sockaddr *)&server, sizeof(server)) != 0)
            {
                cerr << "connect error: " << errno << " : " << strerror(errno) << endl;
                exit(CONNECT_ERROR);
            }

            // 开始通信
            string msg;
            char buffer[g_num];

            while (true)
            {
                cout << "Please Enter# ";
                getline(cin, msg);

                // 发送
                write(_sockfd, msg.c_str(), msg.size());// 将消息写到服务端
                // 接收
                int n = read(_sockfd, buffer, sizeof(buffer) - 1);
                if(n > 0)
                {
                    buffer[n] = 0;// 字符串
                    cout << "Server回送# " << buffer << endl;
                }
                else break;
            }
        }

    private:
        string _serverIP;
        uint16_t _serverPort;
        int _sockfd;
    };
}